package controller

import (
	"context"
	"gf-mysql-transfer/api/v1"
	"gf-mysql-transfer/internal/global"
	"gf-mysql-transfer/internal/metrics"
	"gf-mysql-transfer/internal/service"
	"github.com/go-mysql-org/go-mysql/mysql"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"net/http"
)

var (
	Index = cIndex{}
)

type cIndex struct{}

func (c *cIndex) Monitor(ctx context.Context, req *v1.MonitorReq) (res *v1.MonitorRes, err error) {
	pos, _ := service.TransferServiceIns().Position()

	var tables []string
	for _, v := range global.RuleKeyList() {
		tables = append(tables, v)
	}

	var insertAmounts = make(map[string]uint64, 0)
	for _, v := range tables {
		insertAmounts[v] = metrics.LabInsertAmount(v)
	}

	var updateAmounts = make(map[string]uint64, 0)
	for _, v := range tables {
		updateAmounts[v] = metrics.LabUpdateRecord(v)
	}

	var deleteAmounts = make(map[string]uint64, 0)
	for _, v := range tables {
		deleteAmounts[v] = metrics.LabDeleteRecord(v)
	}
	res = &v1.MonitorRes{
		Mysql:         global.Cfg().Addr,
		BinName:       pos.Name,
		BinPos:        pos.Pos,
		DestName:      global.Cfg().DestStdName(),
		DestAddr:      global.Cfg().DestAddr(),
		DestState:     metrics.DestState(),
		BootTime:      gtime.New(global.BootTime()).String(),
		InsertAmount:  metrics.InsertAmount(),
		UpdateAmount:  metrics.UpdateAmount(),
		DeleteAmount:  metrics.DeleteAmount(),
		Tables:        tables,
		InsertAmounts: insertAmounts,
		UpdateAmounts: updateAmounts,
		DeleteAmounts: deleteAmounts,
		IsCluster:     global.Cfg().IsCluster(),
	}

	if global.Cfg().IsCluster() {
		res.IsZk = global.Cfg().IsZk()
		res.ZkAddress = global.Cfg().Cluster.ZkAddrs
		res.IsEtcd = global.Cfg().IsEtcd()
		res.EtcdAddress = global.Cfg().Cluster.EtcdAddrs
		res.IsLeader = global.IsLeader()
		res.Leader = global.LeaderNode()
		var followers []string
		for _, v := range service.ClusterServiceIns().Nodes() {
			if v != global.LeaderNode() {
				followers = append(followers, v)
			}
		}
		res.Followers = followers
	}
	return
}

func (c *cIndex) Ping(ctx context.Context, req *v1.PingReq) (res *v1.PingRes, err error) {
	err = service.Ping()
	if err != nil {
		g.RequestFromCtx(ctx).Response.WriteStatusExit(http.StatusInternalServerError, err.Error())
	}
	res = &v1.PingRes{}
	return
}

func (c *cIndex) Position(ctx context.Context, req *v1.PositionReq) (res *v1.PositionRes, err error) {
	err = service.TransferServiceIns().UpdatePosition(ctx, mysql.Position{
		Name: req.Name,
		Pos:  req.Pos,
	})
	return
}
